{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/jd4615/miniconda3/envs/insightface/lib/python2.7/site-packages/sklearn/utils/fixes.py:313: FutureWarning: numpy not_equal will not check object identity in the future. The comparison did not return the same result as suggested by the identity (`is`)) and will change.\n",
      "  _nan_object_mask = _nan_object_array != _nan_object_array\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import numpy as np\n",
    "import cPickle\n",
    "from sklearn.metrics import roc_curve, auc\n",
    "import matplotlib.pyplot as plt\n",
    "import timeit\n",
    "import sklearn\n",
    "import cv2\n",
    "import sys\n",
    "import glob\n",
    "sys.path.append('./recognition')\n",
    "from embedding import Embedding\n",
    "from menpo.visualize import print_progress\n",
    "from menpo.visualize.viewmatplotlib import sample_colours_from_colourmap\n",
    "from prettytable import PrettyTable\n",
    "from pathlib import Path\n",
    "import warnings \n",
    "warnings.filterwarnings(\"ignore\")  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def read_template_media_list(path):\n",
    "    ijb_meta = np.loadtxt(path, dtype=str)\n",
    "    templates = ijb_meta[:,1].astype(np.int)\n",
    "    medias = ijb_meta[:,2].astype(np.int)\n",
    "    return templates, medias"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def read_template_pair_list(path):\n",
    "    pairs = np.loadtxt(path, dtype=str)\n",
    "    t1 = pairs[:,0].astype(np.int)\n",
    "    t2 = pairs[:,1].astype(np.int)\n",
    "    label = pairs[:,2].astype(np.int)\n",
    "    return t1, t2, label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def read_image_feature(path):\n",
    "    with open(path, 'rb') as fid:\n",
    "        img_feats = cPickle.load(fid)\n",
    "    return img_feats"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_image_feature(img_path, img_list_path, model_path, gpu_id):\n",
    "    img_list = open(img_list_path)\n",
    "    embedding = Embedding(model_path, 0, gpu_id)\n",
    "    files = img_list.readlines()\n",
    "    img_feats = []\n",
    "    faceness_scores = []\n",
    "    for img_index, each_line in enumerate(print_progress(files)):\n",
    "        name_lmk_score = each_line.strip().split(' ')\n",
    "        img_name = os.path.join(img_path, name_lmk_score[0])\n",
    "        img = cv2.imread(img_name)\n",
    "        lmk = np.array([float(x) for x in name_lmk_score[1:-1]], dtype=np.float32)\n",
    "        lmk = lmk.reshape( (5,2) )\n",
    "        img_feats.append(embedding.get(img,lmk))\n",
    "        faceness_scores.append(name_lmk_score[-1])\n",
    "    img_feats = np.array(img_feats).astype(np.float32)\n",
    "    faceness_scores = np.array(faceness_scores).astype(np.float32)\n",
    "    return img_feats, faceness_scores"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def image2template_feature(img_feats = None, templates = None, medias = None):\n",
    "    # ==========================================================\n",
    "    # 1. face image feature l2 normalization. img_feats:[number_image x feats_dim]\n",
    "    # 2. compute media feature.\n",
    "    # 3. compute template feature.\n",
    "    # ==========================================================    \n",
    "    unique_templates = np.unique(templates)\n",
    "    template_feats = np.zeros((len(unique_templates), img_feats.shape[1]))\n",
    "\n",
    "    for count_template, uqt in enumerate(unique_templates):\n",
    "        (ind_t,) = np.where(templates == uqt)\n",
    "        face_norm_feats = img_feats[ind_t]\n",
    "        face_medias = medias[ind_t]\n",
    "        unique_medias, unique_media_counts = np.unique(face_medias, return_counts=True)\n",
    "        media_norm_feats = []\n",
    "        for u,ct in zip(unique_medias, unique_media_counts):\n",
    "            (ind_m,) = np.where(face_medias == u)\n",
    "            if ct == 1:\n",
    "                media_norm_feats += [face_norm_feats[ind_m]]\n",
    "            else: # image features from the same video will be aggregated into one feature\n",
    "                media_norm_feats += [np.mean(face_norm_feats[ind_m], 0, keepdims=True)]\n",
    "        media_norm_feats = np.array(media_norm_feats)\n",
    "        # media_norm_feats = media_norm_feats / np.sqrt(np.sum(media_norm_feats ** 2, -1, keepdims=True))\n",
    "        template_feats[count_template] = np.sum(media_norm_feats, 0)\n",
    "        if count_template % 2000 == 0: \n",
    "            print('Finish Calculating {} template features.'.format(count_template))\n",
    "    template_norm_feats = template_feats / np.sqrt(np.sum(template_feats ** 2, -1, keepdims=True))\n",
    "    return template_norm_feats, unique_templates"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "def verification(template_norm_feats = None, unique_templates = None, p1 = None, p2 = None):\n",
    "    # ==========================================================\n",
    "    #         Compute set-to-set Similarity Score.\n",
    "    # ==========================================================\n",
    "    template2id = np.zeros((max(unique_templates)+1,1),dtype=int)\n",
    "    for count_template, uqt in enumerate(unique_templates):\n",
    "        template2id[uqt] = count_template\n",
    "    \n",
    "    score = np.zeros((len(p1),))   # save cosine distance between pairs \n",
    "\n",
    "    total_pairs = np.array(range(len(p1)))\n",
    "    batchsize = 100000 # small batchsize instead of all pairs in one batch due to the memory limiation\n",
    "    sublists = [total_pairs[i:i + batchsize] for i in range(0, len(p1), batchsize)]\n",
    "    total_sublists = len(sublists)\n",
    "    for c, s in enumerate(sublists):\n",
    "        feat1 = template_norm_feats[template2id[p1[s]]]\n",
    "        feat2 = template_norm_feats[template2id[p2[s]]]\n",
    "        similarity_score = np.sum(feat1 * feat2, -1)\n",
    "        score[s] = similarity_score.flatten()\n",
    "        if c % 10 == 0:\n",
    "            print('Finish {}/{} pairs.'.format(c, total_sublists))\n",
    "    return score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def read_score(path):\n",
    "    with open(path, 'rb') as fid:\n",
    "        img_feats = cPickle.load(fid)\n",
    "    return img_feats"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step1: Load Meta Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time: 1.73 s. \n"
     ]
    }
   ],
   "source": [
    "# =============================================================\n",
    "# load image and template relationships for template feature embedding\n",
    "# tid --> template id,  mid --> media id \n",
    "# format:\n",
    "#           image_name tid mid\n",
    "# =============================================================\n",
    "start = timeit.default_timer()\n",
    "templates, medias = read_template_media_list(os.path.join('IJBC/meta', 'ijbc_face_tid_mid.txt'))\n",
    "stop = timeit.default_timer()\n",
    "print('Time: %.2f s. ' % (stop - start))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time: 63.98 s. \n"
     ]
    }
   ],
   "source": [
    "# =============================================================\n",
    "# load template pairs for template-to-template verification\n",
    "# tid : template id,  label : 1/0\n",
    "# format:\n",
    "#           tid_1 tid_2 label\n",
    "# =============================================================\n",
    "start = timeit.default_timer()\n",
    "p1, p2, label = read_template_pair_list(os.path.join('IJBC/meta', 'ijbc_template_pair_label.txt'))\n",
    "stop = timeit.default_timer()\n",
    "print('Time: %.2f s. ' % (stop - start))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step 2: Get Image Features"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('loading', './pretrained_models/MS1MV2-ResNet100-Arcface/model', 0)\n",
      "[====================] 100% (469375/469375) - done.                             \n",
      "Time: 6806.24 s. \n",
      "Feature Shape: (469375 , 1024) .\n"
     ]
    }
   ],
   "source": [
    "# =============================================================\n",
    "# load image features \n",
    "# format:\n",
    "#           img_feats: [image_num x feats_dim] (227630, 512)\n",
    "# =============================================================\n",
    "start = timeit.default_timer()\n",
    "#img_feats = read_image_feature('./MS1MV2/IJBB_MS1MV2_r100_arcface.pkl')\n",
    "img_path = './IJBC/loose_crop'\n",
    "img_list_path = './IJBC/meta/ijbc_name_5pts_score.txt'\n",
    "model_path = './pretrained_models/MS1MV2-ResNet100-Arcface/model'\n",
    "gpu_id = 1\n",
    "img_feats, faceness_scores = get_image_feature(img_path, img_list_path, model_path, gpu_id)\n",
    "stop = timeit.default_timer()\n",
    "print('Time: %.2f s. ' % (stop - start))\n",
    "print('Feature Shape: ({} , {}) .'.format(img_feats.shape[0], img_feats.shape[1]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step3: Get Template Features"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finish Calculating 0 template features.\n",
      "Finish Calculating 2000 template features.\n",
      "Finish Calculating 4000 template features.\n",
      "Finish Calculating 6000 template features.\n",
      "Finish Calculating 8000 template features.\n",
      "Finish Calculating 10000 template features.\n",
      "Finish Calculating 12000 template features.\n",
      "Finish Calculating 14000 template features.\n",
      "Finish Calculating 16000 template features.\n",
      "Finish Calculating 18000 template features.\n",
      "Finish Calculating 20000 template features.\n",
      "Finish Calculating 22000 template features.\n",
      "Time: 7.85 s. \n"
     ]
    }
   ],
   "source": [
    "# =============================================================\n",
    "# compute template features from image features.\n",
    "# =============================================================\n",
    "start = timeit.default_timer()\n",
    "# ========================================================== \n",
    "# Norm feature before aggregation into template feature?\n",
    "# Feature norm from embedding network and faceness score are able to decrease weights for noise samples (not face).\n",
    "# ========================================================== \n",
    "# 1. FaceScore （Feature Norm）\n",
    "# 2. FaceScore （Detector）\n",
    "\n",
    "use_norm_score = False # if Ture, TestMode(N1)  \n",
    "use_detector_score = False # if Ture, TestMode(D1)\n",
    "use_flip_test = False # if Ture, TestMode(F1)\n",
    "\n",
    "if use_flip_test:\n",
    "    # concat --- F1\n",
    "    #img_input_feats = img_feats \n",
    "    # add --- F2\n",
    "    img_input_feats = img_feats[:,0:img_feats.shape[1]/2] + img_feats[:,img_feats.shape[1]/2:]\n",
    "else:\n",
    "    img_input_feats = img_feats[:,0:img_feats.shape[1]/2]\n",
    "    \n",
    "if use_norm_score:\n",
    "    img_input_feats = img_input_feats\n",
    "else:\n",
    "    # normalise features to remove norm information\n",
    "    img_input_feats = img_input_feats / np.sqrt(np.sum(img_input_feats ** 2, -1, keepdims=True))    \n",
    "    \n",
    "if use_detector_score:\n",
    "    img_input_feats = img_input_feats * np.matlib.repmat(faceness_scores[:,np.newaxis], 1, img_input_feats.shape[1])\n",
    "else:\n",
    "    img_input_feats = img_input_feats\n",
    "\n",
    "template_norm_feats, unique_templates = image2template_feature(img_input_feats, templates, medias)\n",
    "stop = timeit.default_timer()\n",
    "print('Time: %.2f s. ' % (stop - start))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step 4: Get Template Similarity Scores"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finish 0/157 pairs.\n",
      "Finish 10/157 pairs.\n",
      "Finish 20/157 pairs.\n",
      "Finish 30/157 pairs.\n",
      "Finish 40/157 pairs.\n",
      "Finish 50/157 pairs.\n",
      "Finish 60/157 pairs.\n",
      "Finish 70/157 pairs.\n",
      "Finish 80/157 pairs.\n",
      "Finish 90/157 pairs.\n",
      "Finish 100/157 pairs.\n",
      "Finish 110/157 pairs.\n",
      "Finish 120/157 pairs.\n",
      "Finish 130/157 pairs.\n",
      "Finish 140/157 pairs.\n",
      "Finish 150/157 pairs.\n",
      "Time: 67.17 s. \n"
     ]
    }
   ],
   "source": [
    "# =============================================================\n",
    "# compute verification scores between template pairs.\n",
    "# =============================================================\n",
    "start = timeit.default_timer()\n",
    "score = verification(template_norm_feats, unique_templates, p1, p2)\n",
    "stop = timeit.default_timer()\n",
    "print('Time: %.2f s. ' % (stop - start))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "score_save_name = './IJBC/result/MS1MV2-ResNet100-ArcFace-TestMode(N0D0F0).npy'\n",
    "np.save(score_save_name, score)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Step 5: Get ROC Curves and TPR@FPR Table"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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tfzyl79s16acnByOO+64vX7X8/LyuPfee5k3bx51dXWICCeddBKFhYXd1m/q1Kn079+/XfqIESPYsmULO3bsaPdZR22ZM2cOd999N+vWrWPLli3dqvtXv/oVd955J4MHDwYS/9vf/e53u217R6xcuZJJkybh9/txu91MmzYt+XT18ccfc9xxxwEwffp0nnrqqS9UVwvPP/8848ePp6KiAoABAwZgWRY5OTnJmY9er5dx48axadOmdudblkU4HCYQCOB2u3n55ZcZNmwYhx12WJt8Z599No891jviy3Znz/FngKNFZATwIPAP4K/AGek0rDPq6+szUW2vZMGCBcycOTPt9fzna3/d52X+6fiv7T3TXvjggw94+umnefPNN2lqauLaa69l7ty5jBgxgpqaGt5//30gNZf/nnvu4Xe/+12bbpnp06dzySWX4DgOjz/+OPfffz+33norkLhBrly5kuXLl7Njxw6OPvpoTjjhBBYtWsQnn3zCihUr+Oyzzxg7diyXXXYZ4XCYK6+8kmeffZYBAwbw2GOP8bOf/Yx7772XN954g2984xtt7D/++ON58sknef3113G5uvOv2J78/HyGDRvG2rVrGT9+PABNTU0d5j3//PPx+/1AYp+KvXVzjBs3jjfffLPdBIw927J+/Xp27drF+PHjOe+885g3bx5XXnnlXm3/8MMPkzZ3xSOPPMKdd97ZLn3UqFE8/vjjbdIqKiq4+eab2bVrF16vl3/84x+ccMIJQOKH1j/+8Q/OOOMMnnjiCTZu3NhhfSLCiSeeiIhw+eWXc8klqdUHv/nNb3jggQc45phj+J//+R/y8/NZs2YNqsqMGTOoqanh61//Otdcc02bMnfv3s1zzz3Hj3/843b1XXfddZx44okUFxfz6KOPcs455/DEE0+0y1dZWcnixYv3qtf+oDvfVkdVoyLyFeAeVf2tiGRsVpXjOHvPdJDQ0redbvbFTT4dvPTSS7z99ttMmDCBeDxOJBJh6NChnHLKKaxevZof/OAHnH766cyYMaPTMtxuN5MmTWLu3LnE43FKSkqSn73++utceOGF2LbN4MGDmTJlCkuXLuXVV1/lwgsvxLIsSkpKmDZtGpD4tfvhhx8mxypal7dlyxYGDhzYrv7rr7+eX/ziF9x8882fWwfdI1DpnsctPP744+3GMrpi0KBBfPbZZ+3S92zL3LlzOf/884HEE9zll1/OlVde2em00J5OF/3Wt77Ft771rW7lLS8v5+qrr+bkk08mJyeHiooKbNsGEuMpV155JTfddBOzZs3qdGX14sWLKS4uZuvWrUyfPp0xY8Zw7LHHcsUVV3DzzTcjIsyePZtrr72We++9l1gsxhtvvMGSJUvw+Xx86UtfYsKECcmnjWg0yvnnn88111zT4Va2M2fOTP4AfOCBB5g1axYffvghd911F/379+c3v/kNfr8fl8uFiBAMBpM/ADJFdxYAxkTkPOCbJJ42ANK3lt1g6Caqyne+8x2qq6t57bXXWL16NT/72c8oLCzkvffe4/jjj+f3v/89//mf/9llORdccAFXXHFF8ub3Rew58sgjqa6uprq6mvfff5/nn38eAL/f3+GirBkzZlBbW8vnjfhcV1fHxo0bOeKII76Q7R0RCoU6vEHt2ZY5c+Zw3333UVpayle+8hXeffdd1q1bh23bWJZFLBZL5t21axcDBgwAYOzYsbzzzjt7teORRx5JDki3fnV2vS699FLeffddXn31VfLy8hg5cmSyvhdffJF33nmHc889l8MPP7zD84uLiwEYPHgws2bN4q23EkE0ioqKkm36j//4j2R6SUkJU6dOpbCwkOzsbE499VTeffddIPGduOSSSygvL+f73/9+l+1samri0Ucf5bLLLuPmm2/mkUceYeLEicmuVIBIJNIrQsV3d+X4l4A7VHWdiAwH5qTXrM5p+fVgSHRTHMycfPLJzJs3j5qaGmzbZufOnXz66afs2LEDVeW8887jlltuSf4T5+bmdrgOaNq0aVx33XXtbkTHH388c+fOxXEctm3bxhtvvMGECRM44YQTePzxx3Ech82bN/PKK68AiRvT5s2bkzeUSCTChx9+CMCYMWNYu3Zth+24/vrrueOOO3rc/oaGBr73ve9x3nnnkZeXl0zfV3vWrFmzhvLy8nbprduyYsUKYrEYmzdvZv369axfvz7ZZQhwwgkn8Ne/Jro6A4EATzzxBF/60pcAmD17Nj/60Y+S40DhcJj777+/XX3f+ta3ks649WvPbqoWtm/fDiS60BYsWMAFF1zQJt1xHH75y19y2WWXtTu3sbExOduqqamJF198MalB67Gbp59+Opl+6qmnUl1dTTAYJBaL8eqrrzJ27NhkG0OhEL/+9a87UTnFbbfdxtVXX43L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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "score_save_path = './IJBC/result'\n",
    "files = glob.glob(score_save_path + '/MS1MV2*.npy')  \n",
    "methods = []\n",
    "scores = []\n",
    "for file in files:\n",
    "    methods.append(Path(file).stem)\n",
    "    scores.append(np.load(file)) \n",
    "methods = np.array(methods)\n",
    "scores = dict(zip(methods,scores))\n",
    "colours = dict(zip(methods, sample_colours_from_colourmap(methods.shape[0], 'Set2')))\n",
    "#x_labels = [1/(10**x) for x in np.linspace(6, 0, 6)]\n",
    "x_labels = [10**-6, 10**-5, 10**-4,10**-3, 10**-2, 10**-1]\n",
    "tpr_fpr_table = PrettyTable(['Methods'] + map(str, x_labels))\n",
    "fig = plt.figure()\n",
    "for method in methods:\n",
    "    fpr, tpr, _ = roc_curve(label, scores[method])\n",
    "    roc_auc = auc(fpr, tpr)\n",
    "    fpr = np.flipud(fpr)\n",
    "    tpr = np.flipud(tpr) # select largest tpr at same fpr\n",
    "    plt.plot(fpr, tpr, color=colours[method], lw=1, label=('[%s (AUC = %0.4f %%)]' % (method.split('-')[-1], roc_auc*100)))\n",
    "    tpr_fpr_row = []\n",
    "    tpr_fpr_row.append(method)\n",
    "    for fpr_iter in np.arange(len(x_labels)):\n",
    "        _, min_index = min(list(zip(abs(fpr-x_labels[fpr_iter]), range(len(fpr)))))\n",
    "        tpr_fpr_row.append('%.4f' % tpr[min_index])\n",
    "    tpr_fpr_table.add_row(tpr_fpr_row)\n",
    "plt.xlim([10**-6, 0.1])\n",
    "plt.ylim([0.3, 1.0])\n",
    "plt.grid(linestyle='--', linewidth=1)\n",
    "plt.xticks(x_labels) \n",
    "plt.yticks(np.linspace(0.3, 1.0, 8, endpoint=True)) \n",
    "plt.xscale('log')\n",
    "plt.xlabel('False Positive Rate')\n",
    "plt.ylabel('True Positive Rate')\n",
    "plt.title('ROC on IJB-C')\n",
    "plt.legend(loc=\"lower right\")\n",
    "plt.show()\n",
    "#fig.savefig('IJB-B.pdf')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+-------------------------------------------+--------+--------+--------+--------+--------+--------+\n",
      "|                  Methods                  | 1e-06  | 1e-05  | 0.0001 | 0.001  |  0.01  |  0.1   |\n",
      "+-------------------------------------------+--------+--------+--------+--------+--------+--------+\n",
      "| MS1MV2-ResNet100-ArcFace-TestMode(N1D1F1) | 0.8997 | 0.9434 | 0.9618 | 0.9744 | 0.9832 | 0.9907 |\n",
      "| MS1MV2-ResNet100-ArcFace-TestMode(N0D1F2) | 0.8829 | 0.9400 | 0.9607 | 0.9746 | 0.9833 | 0.9910 |\n",
      "| MS1MV2-ResNet100-ArcFace-TestMode(N1D1F2) | 0.8985 | 0.9447 | 0.9628 | 0.9753 | 0.9836 | 0.9908 |\n",
      "| MS1MV2-ResNet100-ArcFace-TestMode(N1D0F0) | 0.8906 | 0.9394 | 0.9603 | 0.9731 | 0.9829 | 0.9904 |\n",
      "| MS1MV2-ResNet100-ArcFace-TestMode(N0D0F0) | 0.8625 | 0.9315 | 0.9565 | 0.9720 | 0.9818 | 0.9901 |\n",
      "| MS1MV2-ResNet100-ArcFace-TestMode(N1D1F0) | 0.8943 | 0.9413 | 0.9610 | 0.9735 | 0.9829 | 0.9905 |\n",
      "| MS1MV2-ResNet100-ArcFace-TestMode(N0D1F0) | 0.8795 | 0.9387 | 0.9591 | 0.9731 | 0.9824 | 0.9904 |\n",
      "+-------------------------------------------+--------+--------+--------+--------+--------+--------+\n"
     ]
    }
   ],
   "source": [
    "print(tpr_fpr_table)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# setting N1D1F2 is the best"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
